namespace KillerKitty {


	//A helper class to deal with MD5s
	class MD5 {
	public:
		static void generateMD5(char *fname, char *digest);

	};

	//fname : filename, digest : pointer to 32+1 byte char array
	void MD5::generateMD5(char *fname, char *digest) {
		char *hexChars = "01234567890abcdef";
		unsigned char udigest[16];	//the generated hash is stored here
		
		if(md5_file(fname,udigest)!=0) {
			string sFile(fname);
			log.write(NULL,"Cannot create digest for file :"+sFile,error);
			return;
		}
		//to convert form the 16 byte array to hex string eg : 206 is ce in hex
		for(int i=0;i<16;i++) {
			//faster version of below code
			digest[(i*2)] = hexChars[(udigest[i]&0xF0)>>4]; //print first 4 bits as hex
			digest[(i*2)+1] = hexChars[udigest[i]&0x0F]; //print last 4 bits as hex

			//sprintf(digest+(i*2),"%x",(udigest[i]&0xF0)>>4);	
			//sprintf(digest+(i*2)+1,"%x",udigest[i]&0x0F);	
		}
		digest[32]='\0';
	}

	//Helper class to read PE files
	//Refer http://www.skynet.ie/~caolan/publink/winresdump/winresdump/doc/pefile.html for more info
	//some of the code is from there
	//FIXME: Much of the code here is not portable in its current state
	class PEReader {
//defines
#define SIZE_OF_NT_SIGNATURE (sizeof(DWORD))
#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + ((PIMAGE_DOS_HEADER)a)->e_lfanew))
#define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a + ((PIMAGE_DOS_HEADER)a)->e_lfanew + SIZE_OF_NT_SIGNATURE))
#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + ((PIMAGE_DOS_HEADER)a)->e_lfanew + SIZE_OF_NT_SIGNATURE + sizeof (IMAGE_FILE_HEADER)))
#define SECHDROFFSET(ptr) ((LPVOID)((BYTE *)(ptr)+((PIMAGE_DOS_HEADER)(ptr))->e_lfanew+SIZE_OF_NT_SIGNATURE+sizeof(IMAGE_FILE_HEADER)+sizeof(IMAGE_OPTIONAL_HEADER)))

	private:
		static DWORD WINAPI ImageFileType (LPVOID    lpFile) {
			/* DOS file signature comes first. */
			if (*(USHORT *)lpFile == IMAGE_DOS_SIGNATURE) {
				/* Determine location of PE File header from DOS header. */
				if (LOWORD (*(DWORD *)NTSIGNATURE (lpFile)) ==	IMAGE_OS2_SIGNATURE ||
					LOWORD (*(DWORD *)NTSIGNATURE (lpFile)) == IMAGE_OS2_SIGNATURE_LE)
					return (DWORD)LOWORD(*(DWORD *)NTSIGNATURE (lpFile));
				else if (*(DWORD *)NTSIGNATURE (lpFile) ==	IMAGE_NT_SIGNATURE)
					return IMAGE_NT_SIGNATURE;
				else
					return IMAGE_DOS_SIGNATURE;
			}
			else /* unknown file type */
				return 0;
		}

		static int WINAPI NumOfSections (LPVOID    lpFile) {
			/* Number of sections is indicated in file header. */
			return (int)(((PIMAGE_FILE_HEADER) PEFHDROFFSET (lpFile))->NumberOfSections);
		}

	public:
		//get EP in case of a PE file
		static unsigned long getEP(unsigned char *file) {

			switch(ImageFileType(file)) {
				//if it is a dos header, directly amp file to stuct and return IP value
				case IMAGE_DOS_SIGNATURE:
					PIMAGE_DOS_HEADER pdh;
					pdh = (PIMAGE_DOS_HEADER) file;
					return pdh->e_ip;
				//if NT header (PE) first get offset of the PE header and get EP value from there
				case IMAGE_NT_SIGNATURE:
					PIMAGE_OPTIONAL_HEADER poh;
				    poh = (PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET (file);
					if (poh != NULL) return poh->AddressOfEntryPoint;
					else return 0;
					break;

				default:
					//handlers for other images file types go here
					break;
			}
			return 0;
		}

		//get the offest of the section specified (starting from 0)
		static long getSectionAddress(unsigned char *file, unsigned short section) {
		
			if(ImageFileType(file) != IMAGE_NT_SIGNATURE) return 0;	//return 0 if file is not a PE file

			PIMAGE_SECTION_HEADER psh;
			int nSections = NumOfSections (file);
			PIMAGE_OPTIONAL_HEADER poh;
		    poh = (PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET (file);

			if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (file)) == NULL || section>=nSections) return 0;
			
			psh+=section;

			return psh->VirtualAddress + poh->ImageBase;	//quite possibly very wrong....
		}

#undef SIZE_OF_NT_SIGNATURE
#undef NTSIGNATURE
#undef PEFHDROFFSET
#undef OPTHDROFFSET
#undef SECHDROFFSET
	};

}
